%{
#include <stdio.h>
#include <string.h>
#include "interpretador.h"

extern int yylineno;
extern char* yytext[];
extern FILE* outFile_p;
extern int yylex();


void yyerror(const char *str)
{
  fprintf(stderr,"Erro: %s\n",str);
}

%}

%token <palavra> SEMICOLON <palavra> OPENPAR  <palavra> CLOSEPAR <palavra> SUM  <palavra> SUB <palavra> MULT <palavra> DIV  <palavra> ATTRIB <palavra> WRITESTR <palavra>  WRITEVAR <palavra> WRITELN <palavra> READ  <palavra> FOR 
%token <palavra> TO <palavra> DO  <palavra> END  <palavra> IF  <palavra> THEN  <palavra> ELSE  <palavra> ENDP  <palavra> STRING  <num>VALUE  <palavra> VARIABLE  <palavra> WHILE <palavra> EQUALS <palavra> OR <palavra> AND <palavra> SQRT <palavra> DOWNTO <palavra> ENDIF <palavra> ENDW <palavra> ENDFOR <palavra> GEQ <palavra> LEQ <palavra> LESS <palavra> GREATER <palavra> LOCAL <palavra> GLOBAL <palavra> CALL <palavra> PROC <palavra> TOKENMAIN <palavra> IDENTIFIER <palavra> ENDPROC <palavra> COMA

%union {
	char *palavra;
	double num;
	Interpretador *interpretador;
	Comandos *comandos;
	Comando *comando;
	Expressao *exp;
	VariableExp *variable;
}

%type <interpretador> programa 
%type <comandos> lista_comandos lista_main 
%type <comando> comando 
%type <exp> expression exp_soma exp_sqrt exp_neg exp_mult termo

%start programa
%%

programa:	
      /*empty*/ {
				printf("\tPrograma vazio\n\n");
			}
			| ENDP {
				printf("\tPrograma que nao faz nada\n\n");
			}
			| GLOBAL lista_dec_global SEMICOLON lista_main {
				printf("Reconheceu global \n\n");
				/*	Instanciaria um objeto da class Global*/
			}
			| lista_main {
				printf("Reconheceu sem  global \n\n");	
			}
		 	;
			
			
lista_main:
		 lista_proc PROC TOKENMAIN OPENPAR CLOSEPAR lista_comandos ENDPROC{
				Context context;
				/* Instanciaria um objeto da class procedure com o nome igual main e lista_comandos = $6,
				   Apos isto iria invocar o metodo interpreta deste objeto
				*/	
			}
		 	lista_proc PROC TOKENMAIN OPENPAR CLOSEPAR LOCAL lista_dec SEMICOLON lista_comandos ENDPROC{
				Context context;
				/* Instanciaria um objeto da class procedure com o nome igual main e lista_comandos = $9,
				   Apos isto iria invocar o metodo interpreta deste objeto
				*/	

			}
		 	| PROC TOKENMAIN OPENPAR CLOSEPAR lista_comandos ENDPROC {
				/* Instanciaria um objeto da class procedure com o nome igual main e lista_comandos = $5,
				   Apos isto iria invocar o metodo interpreta deste objeto
				*/	
				Context context;

			}
			;
lista_proc:
		lista_proc PROC IDENTIFIER OPENPAR lista_dec CLOSEPAR lista_comandos ENDPROC{
				/*Instanciaria um objeto da class procedure, onde comand_lista seria $7 e o nome = $3
				Alem disto chamaria o metodo insere_procedure da class global para adicionar o objeto procedure
				 */

			}
			| lista_proc PROC IDENTIFIER OPENPAR lista_dec CLOSEPAR LOCAL lista_dec lista_comandos ENDPROC{
				/*Instanciaria um objeto da class procedure, onde comand_lista seria $9 e o nome = $3
				Alem disto chamaria o metodo insere_procedure da class global para adicionar o objeto procedure
				 */
			}
			| PROC IDENTIFIER OPENPAR lista_dec CLOSEPAR lista_comandos ENDPROC {
				/*Instanciaria um objeto da class procedure, onde comand_lista seria $6 e o nome = $2
				Alem disto chamaria o metodo insere_procedure da class global para adicionar o objeto procedure
				 */

			}
			| PROC IDENTIFIER OPENPAR lista_dec CLOSEPAR LOCAL lista_dec SEMICOLON lista_comandos ENDPROC {
				/*Instanciaria um objeto da class procedure, onde comand_lista seria $9 e o nome = $2
				Alem disto chamaria o metodo insere_procedure da class global para adicionar o objeto procedure
				 */

			}
			;

lista_dec:
			VARIABLE {
				/* chamaria o metodo inserir da class Procedure*/
			}
			| lista_dec COMA VARIABLE{
				/* chamaria o metodo inserir da class Procedure*/

			}
			;
lista_dec_global:
			VARIABLE {
				/* chamaria o metodo inserir da class Global*/
			}
			| lista_dec COMA VARIABLE{
				/* chamaria o metodo inserir da class Global*/

			}
			;

lista_comandos:	
      comando {
				$$ = new Comandos($1,NULL);
			}
			| comando lista_comandos {
				$$ = new Comandos($1,$2);
			}
			;

comando:	
      WRITESTR OPENPAR STRING CLOSEPAR SEMICOLON {
				$$ = new WriteStr($3);
			}
			| WRITEVAR OPENPAR VARIABLE CLOSEPAR SEMICOLON {
				$$ = new WriteVar($3[0]);
			}
			| WRITELN SEMICOLON {
				$$ = new Writeln();
			}
			| SQRT OPENPAR VALUE CLOSEPAR {
			}
			| READ OPENPAR VARIABLE CLOSEPAR SEMICOLON {
				$$ = new Read($3[0]);
			}
			| VARIABLE ATTRIB expression SEMICOLON {
				$$ = new Atribuir($1[0], $3);
			}
			| FOR VARIABLE ATTRIB expression TO expression DO lista_comandos ENDFOR {
				$$ = new For($2[0], $4, 0, $6,$8);
			}
			| FOR VARIABLE ATTRIB expression DOWNTO expression DO lista_comandos ENDFOR {
				$$ = new For($2[0], $4, 1, $6,$8);
			}
			| WHILE expression DO lista_comandos ENDW {
				$$ = new While($2,$4);
			}
			| IF expression THEN lista_comandos ENDIF {
				$$ = new If($2,$4);
			}
			| IF expression THEN lista_comandos ELSE lista_comandos ENDIF {
				$$ = new IfWithElse($2,$4,$6);
			}
			| CALL IDENTIFIER{
				/* Chamaria o interpreta do objeto da class procedure cujo nome fosse igual a $2 */
			}
			;


expression:	
      expression EQUALS exp_soma {
				$$ = new Equals($1,$3);
			}
			| expression AND exp_soma {
				$$ = new And($1,$3);
			}
			| expression OR exp_soma {
				$$ = new Or($1,$3);
			}
			| expression GEQ exp_soma {
				$$ = new Geq($1,$3);
			}
			| expression LEQ exp_soma {
				$$ = new Leq($1,$3);
			}
			| expression LESS exp_soma {
				$$ = new Less($1,$3);
			}
			| expression GREATER exp_soma {
				$$ = new Greater($1,$3);
			}
			| exp_soma {
				$$ = $1; 
			}
			;	

exp_soma:	
      exp_soma SUM exp_mult {
				$$ = new Sum($1,$3);
			}
			| exp_soma SUB exp_mult {
				$$ = new Sub($1,$3);
			}
			| exp_mult {
				$$ = $1;
			} 
			;

exp_mult:
      exp_mult MULT exp_neg {
				$$ = new Mult($1,$3);
			}
			| exp_mult DIV exp_neg {
				$$ = new Div($1,$3);
			}
			| exp_neg {
				$$ = $1;
			}
			;

exp_neg:	
      SUB exp_sqrt {
				$$ = $2;
			}
			| exp_sqrt {
				$$ = $1;
			}
			;

exp_sqrt:	
      SQRT OPENPAR termo CLOSEPAR {
			 	$$ = new Sqrt($3);			
			}
			| termo {
				$$ = $1;
			}
			;

termo:		
      VALUE {
				$$= new Valor($1);	
			}
			| VARIABLE {
				$$ = new Valor($1[0]); 
			}
			| OPENPAR expression CLOSEPAR {
				$$ = $2;
			}
			;
